package com.sc.nft.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.Lists;
import com.sc.nft.dao.*;
import com.sc.nft.dto.UserFirstBuyDTO;
import com.sc.nft.entity.*;
import com.sc.nft.entity.vo.LockOrderVO;
import com.sc.nft.enums.*;
import com.sc.nft.exception.GlobalRunTimeException;
import com.sc.nft.helper.MessageQueueHelper;
import com.sc.nft.service.*;
import com.sc.nft.sup.ErrorCode;
import com.sc.nft.util.OrderNoUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * 集售订单表服务接口实现
 *
 * @author zxy
 * @description 由 Mybatisplus Code Generator 创建
 * @since 2024-09-18 01:01:58
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CollectiveOrderServiceImpl implements CollectiveOrderService {
    private final CollectiveOrderDao collectiveOrderDao;
    private final CollectiveSalesDao collectiveSalesDao;
    private final CollectiveSalesConfigDao collectiveSalesConfigDao;
    private final DigitalCollectionDao digitalCollectionDao;
    private final ExitConsensusUserDao exitConsensusUserDao;
    private final CollectiveSalesTimePointsDao collectiveSalesTimePointsDao;
    private final UserConsensusService userConsensusService;
    private final UserWalletService userWalletService;
    private final MessageQueueHelper messageQueueHelper;
    private final UserInfoDao userInfoDao;
    private final UserCollectionService userCollectionService;
    private final UserCollectionDao userCollectionDao;
    private final FilterIncomeListDao filterIncomeListDao;
    private final RedisTemplate redisTemplate;
    private final PayOrderDao payOrderDao;
    private final PayOrderItemDao payOrderItemDao;
    private final ScOrderSettleService orderSettleService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public LockOrderVO createOrder(UserInfo userInfo, Long id, Integer count) {
        CollectiveSalesConfig collectiveSalesConfig = collectiveSalesConfigDao.getById(id);
        Assert.isTrue(ObjectUtil.isNotNull(collectiveSalesConfig) && collectiveSalesConfig.getStatus(), () -> new GlobalRunTimeException("该藏品暂不支持集售"));
        Assert.isTrue(collectiveOrderDao.getUserWaitPayOrderCount(userInfo.getId()) == 0, () -> new GlobalRunTimeException(ErrorCode.WAIT_PAY_ORDER));
        LocalTime now = LocalTime.now();
        DateTime dateTime = DateTime.of(now.toString().substring(0, 8), "HH:mm:ss");
        Assert.isTrue(dateTime.isAfter(collectiveSalesConfig.getStartBuyTime()), () -> new GlobalRunTimeException("尚未到达购买时间"));
        Assert.isTrue(dateTime.isBefore(collectiveSalesConfig.getActivityEndTime()), () -> new GlobalRunTimeException("今天活动已结束"));
        List<CollectiveSales> onConsignListLimit = collectiveSalesDao.getOnConsignListLimitNotEqUserId(collectiveSalesConfig.getCollectionId(), count, userInfo.getId());
        Assert.isTrue(onConsignListLimit.size() == count.intValue(), () -> new GlobalRunTimeException("集售挂单量不足"));
        DigitalCollection collection = digitalCollectionDao.getById(collectiveSalesConfig.getCollectionId());
        if (collection.getCollectionType() == DigitalMarketTypeEnum.ECOLOGY) {
            ExitConsensusUser exitConsensusUser = exitConsensusUserDao.getByUserId(userInfo.getId());
            if (ObjectUtil.isNotNull(exitConsensusUser) && exitConsensusUser.getStatus()) {
                throw new GlobalRunTimeException("非共识区用户禁止购买该藏品");
            } else {

            }
        }
        CollectiveSalesTimePoints nowPrice = collectiveSalesTimePointsDao.getNowPrice(collectiveSalesConfig.getId());
        if (nowPrice.getBuyCollectionId() != null) {
            FilterIncomeList filterIncomeList = filterIncomeListDao.getIsTeamIncomeByUserId(userInfo.getId());
            if (ObjectUtil.isNotNull(filterIncomeList)) {

            } else {
                Integer holdCount = userCollectionDao.getUserHoldCollectionByIds(userInfo.getId(), Lists.newArrayList(nowPrice.getBuyCollectionId()));
                Assert.isTrue(holdCount > 0, () -> new GlobalRunTimeException("购买须持有藏品数量不足"));
            }

        }
        BigDecimal gas = collectiveSalesConfig.getGas();
        BigDecimal charge = nowPrice.getPrice().subtract(gas).multiply(collectiveSalesConfig.getServiceFeeRatio()).setScale(2, BigDecimal.ROUND_HALF_UP);
        BigDecimal realAmount = nowPrice.getPrice().subtract(gas).subtract(charge);
        DateTime nowTime = DateTime.now();
        DateTime closeTime = DateTime.now().offsetNew(DateField.MINUTE, 3);
        List<Long> ids = Lists.newArrayList();
        BigDecimal sumAmount = BigDecimal.ZERO;
        for (CollectiveSales collectiveSales : onConsignListLimit) {
            Assert.isTrue(collectiveSalesDao.updateStatusToLock(collectiveSales.getId()), () -> new GlobalRunTimeException("藏品锁定失败，请稍后再试"));
            CollectiveOrder collectiveOrder = new CollectiveOrder();
            collectiveOrder.setCollectionId(collectiveSales.getCollectionId());
            collectiveOrder.setCollectionName(collection.getFirstTitle());
            collectiveOrder.setCollectiveSalesId(collectiveSales.getId());
            collectiveOrder.setOrderTime(nowTime);
            collectiveOrder.setCharge(charge);
            collectiveOrder.setGas(gas);
            collectiveOrder.setCreationContent(collection.getCreationContent());
            collectiveOrder.setBuyPrice(nowPrice.getPrice());
            collectiveOrder.setOrderNo(OrderNoUtil.getOrderNo());
            collectiveOrder.setNumbering(collectiveSales.getNumbering());
            collectiveOrder.setCloseTime(closeTime);
            collectiveOrder.setStatus(OrderStatusEnum.WAIT_PAY);
            collectiveOrder.setUserCollectionId(collectiveSales.getUserCollectionId());
            collectiveOrder.setSettleFlag(false);
            collectiveOrder.setBuyUserId(userInfo.getId());
            collectiveOrder.setSalesUserId(collectiveSales.getUserId());
            collectiveOrder.setRealReceiveAmount(realAmount);
            collectiveOrder.insert();
            sumAmount = sumAmount.add(collectiveOrder.getBuyPrice());
            ids.add(collectiveOrder.getId());
        }
        LockOrderVO lockOrderVO = new LockOrderVO();
        lockOrderVO.setOrderIds(ids);
        lockOrderVO.setMoney(sumAmount);
        lockOrderVO.setSumCount(onConsignListLimit.size());
        lockOrderVO.setNowDate(DateTime.now());
        lockOrderVO.setExpirationTime(closeTime);
        return lockOrderVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrder(UserInfo userInfo, List<Long> ids) {
        List<CollectiveOrder> userWaitPayOrderBuyIds = collectiveOrderDao.getUserWaitPayOrderBuyIds(userInfo.getId(), ids);
        Assert.isTrue(ids.size() == userWaitPayOrderBuyIds.size(), () -> new GlobalRunTimeException("有订单状态发生改变，请刷新后重试"));
        for (CollectiveOrder userWaitPayOrderBuyId : userWaitPayOrderBuyIds) {
            Assert.isTrue(collectiveSalesDao.updateStatusToConsign(userWaitPayOrderBuyId.getCollectiveSalesId()), () -> new GlobalRunTimeException("集售商品状态以改变，请刷新后重试"));
            Assert.isTrue(collectiveOrderDao.updateStatusToClose(userWaitPayOrderBuyId.getId()), () -> new GlobalRunTimeException("订单状态以改变，请刷新后重试"));

        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void cancelOrderById(Long orderId) {
        CollectiveOrder collectiveOrder = collectiveOrderDao.getById(orderId);
        if (collectiveOrder.getStatus() != OrderStatusEnum.WAIT_PAY) {
            log.warn("关闭集售订单失败:{}", collectiveOrder.getOrderNo());
            return;
        }
        Assert.isTrue(collectiveOrderDao.updateStatusToClose(collectiveOrder.getId()), () -> new GlobalRunTimeException(ErrorCode.LATER_TRY));
        Assert.isTrue(collectiveSalesDao.updateStatusToConsign(collectiveOrder.getCollectiveSalesId()), () -> new GlobalRunTimeException(ErrorCode.LATER_TRY));
        String lockKey = RedisKeyEnum.COLLECTIVE_USER_LOCK.getKey() + collectiveOrder.getBuyUserId();
        redisTemplate.opsForValue().increment(lockKey);
        redisTemplate.expire(lockKey, 6, TimeUnit.HOURS);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(List<CollectiveOrder> collectiveOrders) {
        for (CollectiveOrder collectiveOrder : collectiveOrders) {
            paySuccess(collectiveOrder);
        }

        if (ObjectUtil.isNotEmpty(digitalCollectionDao.getEcologyCollectionById(collectiveOrders.get(0).getCollectionId()))) {
            userConsensusService.adjustConsensusService(collectiveOrders.get(0).getBuyUserId(), collectiveOrders.get(0).getCollectionId(), BigDecimal.valueOf(collectiveOrders.size()), UserConsensusTypeEnums.BUY, collectiveOrders.get(0).getCollectionName(), null);
        }
    }

    private void paySuccess(CollectiveOrder collectiveOrder) {
        Assert.notNull(collectiveOrder, () -> new GlobalRunTimeException(ErrorCode.ORDER_NOT_FOUND));
        Assert.isTrue(collectiveOrder.getStatus() == OrderStatusEnum.WAIT_PAY, () -> new GlobalRunTimeException(ErrorCode.ORDER_STATUS_ERROR));
        CollectiveSales collectiveSales = collectiveSalesDao.getById(collectiveOrder.getCollectiveSalesId());
        Assert.isFalse(collectiveOrder.getBuyUserId().longValue() == collectiveSales.getUserId().longValue(), () -> new GlobalRunTimeException(ErrorCode.CANT_BUY_SELF));
        Assert.notNull(collectiveSales, () -> new GlobalRunTimeException(ErrorCode.PRODUCT_NOT_FOUND));
        Assert.isTrue(collectiveSales.getStatus() == ConSignStatus.LOCK, () -> new GlobalRunTimeException(ErrorCode.PRODUCT_NOT_FOUND));
        UserWallet userWallet = userWalletService.getByUserId(collectiveOrder.getBuyUserId());
        if (BeanUtil.isEmpty(collectiveOrder)) {
            throw new GlobalRunTimeException("订单已过期");
        }

        collectiveOrder.setStatus(OrderStatusEnum.PAYMENT);
        collectiveOrder.setPayTime(new Date());
        collectiveOrder.setBuyPrice(collectiveOrder.getBuyPrice());
        collectiveOrderDao.updateById(collectiveOrder);
        //修改用户为用效用户
        UserInfo userInfo = userInfoDao.getById(collectiveOrder.getBuyUserId());
        if (!userInfo.getIsValid()) {
            userInfoDao.setIsValid(userInfo.getId());
            messageQueueHelper.sendMessage(MessageTopic.USER_FIRST_BUY, new UserFirstBuyDTO(userInfo.getId(), collectiveOrder.getId(), 2));

        }
        //藏品转移
        userCollectionService.buyCollective(collectiveOrder);
        collectiveSales.setStatus(ConSignStatus.SUCCESS);
        collectiveSales.setSalesTime(DateTime.now());
        collectiveSalesDao.updateById(collectiveSales);


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void extracted(CollectiveOrder collectiveOrder) {
        // 把钱给寄售人,付款金额减去利息 TODO 改造成分账 6.3.6-pay

        PayOrder payOrder = payOrderItemDao.getByOrderIdAndType(collectiveOrder.getId(), SecondPayOrderItemTypeEnum.COLLECTION,PayTypeEnum.COLLECTIVE);
        //连连走分账 其他走钱包
        if(payOrder.getChannel().equals(PayChannelEnum.LL_PAY)){
            BigDecimal sellerAmount = collectiveOrder.getBuyPrice().subtract(collectiveOrder.getCharge()).subtract(collectiveOrder.getGas());
                    orderSettleService.create(collectiveOrder.getId(), collectiveOrder.getBuyPrice(), collectiveOrder.getOrderNo(), collectiveOrder.getSalesUserId(), payOrder,
                            WalletDetailTypeEnum.COLLECTIVE_SELL, sellerAmount
                            , SettleUserTypeEnum.USER, ExpenditureRecordTypeEnum.SELL, BizTypeEnum.COLLECTION, MarketLevelEnum.SECOND);
            //TODO 订单剩余未分金额归平台 购买金额-用户分账金额=平台所得金额 此处只管卖家付款金额和直推 其他全是平台的 此处没有直推只有手续费
            //TODO 给平台增加待结算 有结余才算否则无意义
            if (collectiveOrder.getBuyPrice().subtract(sellerAmount).compareTo(BigDecimal.ZERO) > 0) {
                orderSettleService.create(collectiveOrder.getId(), collectiveOrder.getBuyPrice(), collectiveOrder.getOrderNo(), null, payOrder, WalletDetailTypeEnum.PLANT_LESS,
                        collectiveOrder.getBuyPrice().subtract(sellerAmount), SettleUserTypeEnum.MERCHANT, ExpenditureRecordTypeEnum.PLANT_AMOUNT, BizTypeEnum.COLLECTION,MarketLevelEnum.SECOND);
            }
        }else {
            userWalletService.addIncomeRemit(collectiveOrder.getSalesUserId(), collectiveOrder.getOrderNo(), collectiveOrder.getBuyPrice(),
                    collectiveOrder.getCharge(), collectiveOrder.getGas(), WalletDetailTypeEnum.COLLECTIVE_SELL, ExpenditureRecordTypeEnum.SELL);
        }

        Assert.isTrue(collectiveOrderDao.updateSettleFlag(collectiveOrder.getId()), () -> new GlobalRunTimeException("寄售订单更新状态失败"));


    }
}